"""物模型分类列组件，包含分类筛选和分类树。"""

from __future__ import annotations

from collections import defaultdict
from typing import Dict, List, Optional

from PySide6.QtCore import Signal
from PySide6.QtWidgets import (
    QComboBox,
    QLabel,
    QTreeWidget,
    QTreeWidgetItem,
    QVBoxLayout,
    QWidget,
)

from src.config import get_iot_model_name
from src.core.models import TypeNode
from src.ui.sidebar import CategoryTree


class CategoryColumn(QWidget):
    """物模型分类列，包含分类筛选和分类树。"""

    category_selected = Signal(int)

    _ALL_KEY = "__all__"
    _ROOT_KEY = "__root__"

    def __init__(self, parent=None) -> None:
        super().__init__(parent)
        self._tree = CategoryTree(self)
        self._filter_label = QLabel("按物模型类别筛选")
        self._filter_selector = QComboBox(self)
        self._filter_selector.setPlaceholderText("选择物模型类别...")
        self._filter_selector.setMinimumHeight(28)

        # 缓存分类数据，避免每次切换都重新计算。
        self._root_nodes: List[TypeNode] = []
        self._node_map: Dict[int, TypeNode] = {}
        self._groups: Dict[Optional[int], List[TypeNode]] = defaultdict(list)

        self._setup_layout()

        self._tree.category_selected.connect(self.category_selected)
        self._filter_selector.currentIndexChanged.connect(self._on_group_changed)
    
    def clear(self) -> None:
        """清空分类列的所有内容和缓存数据。"""
        # 清空分类树
        self._tree.clear()
        self._tree._item_to_node.clear()
        
        # 清空筛选下拉框
        self._filter_selector.blockSignals(True)
        self._filter_selector.clear()
        self._filter_selector.blockSignals(False)
        
        # 清空缓存数据
        self._root_nodes = []
        self._node_map = {}
        self._groups = defaultdict(list)

    def load_categories(self, root_nodes: List[TypeNode], all_nodes: List[TypeNode]) -> None:
        """加载并缓存分类数据，初始化树与下拉选择项。"""
        self._root_nodes = self._sort_nodes(root_nodes)
        self._node_map = {node.id: node for node in all_nodes}
        self._groups = self._build_groups(all_nodes)

        self._populate_filter_selector()
        self._apply_group(self._ALL_KEY)

    # ---------------- 内部工具方法 ---------------- #

    def _setup_layout(self) -> None:
        """设置布局。"""
        layout = QVBoxLayout(self)
        layout.setContentsMargins(8, 8, 8, 8)
        layout.setSpacing(8)
        
        filter_box = QWidget(self)
        filter_layout = QVBoxLayout(filter_box)
        filter_layout.setContentsMargins(0, 0, 0, 0)
        filter_layout.setSpacing(6)
        filter_layout.addWidget(self._filter_label)
        filter_layout.addWidget(self._filter_selector)

        layout.addWidget(filter_box, 0)
        layout.addWidget(self._tree, 1)

    def _build_groups(self, nodes: List[TypeNode]) -> Dict[Optional[int], List[TypeNode]]:
        """构建分组。"""
        grouped: Dict[Optional[int], List[TypeNode]] = defaultdict(list)
        for node in nodes:
            grouped[node.parent_id].append(node)

        for parent_id, items in grouped.items():
            grouped[parent_id] = self._sort_nodes(items)
        return grouped

    def _populate_filter_selector(self) -> None:
        """填充筛选下拉框。"""
        self._filter_selector.blockSignals(True)
        self._filter_selector.clear()

        self._filter_selector.addItem("全部分类", self._ALL_KEY)

        if None in self._groups:
            root_count = len(self._groups[None])
            self._filter_selector.addItem(f"顶级分类（{root_count}）", self._ROOT_KEY)

        parent_ids = [pid for pid in self._groups.keys() if pid is not None]
        parent_ids.sort(key=self._parent_sort_key)

        for parent_id in parent_ids:
            parent_node = self._node_map.get(parent_id)
            # 使用映射表获取物模型名称，如果映射表中不存在则使用原始名称
            if parent_node:
                label = get_iot_model_name(parent_id, parent_node.name)
            else:
                label = get_iot_model_name(parent_id)
            label = f"{label}（{len(self._groups[parent_id])}）"
            self._filter_selector.addItem(label, parent_id)

        self._filter_selector.setCurrentIndex(0)
        self._filter_selector.blockSignals(False)

    def _on_group_changed(self, index: int) -> None:
        """分组选择变化时的处理。"""
        if index < 0:
            return
        key = self._filter_selector.itemData(index)
        self._apply_group(key)

    def _apply_group(self, key) -> None:
        """应用分组筛选。"""
        if key == self._ALL_KEY:
            self._tree.load_nodes(self._root_nodes)
            return

        if key == self._ROOT_KEY:
            nodes = self._groups.get(None, [])
            self._tree.load_nodes(nodes)
            return

        parent_node = self._node_map.get(key) if isinstance(key, int) else None
        if parent_node:
            # 当用户选择具体物模型级节点时，将物模型级节点自身作为根传入，保留上下文层级。
            self._tree.load_nodes([parent_node])
            return

        nodes = self._groups.get(key, [])
        self._tree.load_nodes(nodes)

    def _parent_sort_key(self, parent_id: Optional[int]) -> tuple[int, str]:
        """获取父节点排序键。"""
        if parent_id is None:
            return (0, "")
        parent_node = self._node_map.get(parent_id)
        if not parent_node:
            return (0, str(parent_id))
        return (parent_node.sort_key(), parent_node.name)

    @staticmethod
    def _sort_nodes(nodes: List[TypeNode]) -> List[TypeNode]:
        """排序节点列表。"""
        return sorted(nodes, key=lambda n: (n.sort_key(), n.name))

